package org.zn.note.jdk.thread.util.concurrent;

import org.zn.note.common.util.ThreadUtil;
import org.zn.note.jdk.thread.Task;

import java.util.concurrent.*;

/**
 * @ClassName TestThreadPool
 * @Author zn
 * @Date 2019/3/28 14:31
 **/
public class TestThreadPool {

    public static void main(String[] args) {
        ThreadUtil.printThreadTask("Main", "start.");
        new TestThreadPool().testExecute();
        ThreadUtil.printThreadTask("Main", "finish.");
    }

    /*
JDK1.8
Executor
      void execute(Runnable command);
ExecutorService
      void shutdown();
      <T> Future<T> submit(Callable<T> task);
      Future<T> submit(Runnable task, T result);
      Future<?> submit(Runnable task);
ThreadPoolExecutor

设置：corePoolSize=2  maximumPoolSize=4  ArrayBlockingQueue=10
第1次execute corePoolSize没满，创建了thread-1，直接执行task1
第2次execute corePoolSize没满，创建了thread-2，直接执行task2
第3~12次execute 发现corePoolSize满了, 放到queue （task3~task12）
第13次execute 发现corePoolSize满了、queue满了，maximumPoolSize没满，创建 thread-3  (task13)
第14次execute 发现corePoolSize满了、queue满了，maximumPoolSize没满，创建 thread-4  (task14)
（所有thread只要执行完了就会去 queue取）
第15次execute 发现corePoolSize满了、queue满了，maximumPoolSize满了，main-thread执行rejectedExecution (task15)
。。。  （这是保证每个Task都执行很长时间，线程占满了，队列占满了，才会在第15次 rejected）

coreThread和其他后建的Thread没有任何区别
在不设置 executor.allowCoreThreadTimeOut(true) 或 executor.shutdown()的时候
仅保证最后剩下corePoolSize个线程，但是不一定是thread-1和thread-2
     */
    void testThreadPoolExecutor() {
        int taskNum = 9;
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                // int corePoolSize
                2,
                // int maximumPoolSize
                4,
                // long keepAliveTime
                1L,
                // TimeUnit unit
                TimeUnit.SECONDS,
                // BlockingQueue<Runnable> workQueue
                new ArrayBlockingQueue(5),
//                new LinkedBlockingQueue(),
                // ThreadFactory threadFactory
                Executors.defaultThreadFactory(),
                // RejectedExecutionHandler handler
                new TestRejectedExecutionHandler()
        );
        // 启动1个core-thread
//        executor.prestartCoreThread();
        // 启动所有core-thread
//        executor.prestartAllCoreThreads();
        for (int i = 0; i < taskNum; i++) {
            executor.execute(new Task(i + ""));
//            executor.allowCoreThreadTimeOut(true); // 不保证corePoolSize数，超过空闲时间都停
//            executor.submit(new Task(i+"")); // 执行完任务就停了
        }
        while (Thread.currentThread().isAlive()) {
            ThreadUtil.printThread("executor.isShutdown():" + executor.isShutdown());
            ThreadUtil.printThread("executor.isTerminated():" + executor.isTerminated());
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
//        executor.shutdown();

    }

    void testExecutors() {
//        Executors.defaultThreadFactory();
//        Executors.callable(...);
//        Executors.newCachedThreadPool();
//        Executors.newFixedThreadPool(3);
//        Executors.newSingleThreadExecutor();
//        Executors.newWorkStealingPool();
//        Executors.privilegedThreadFactory();
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3);
        scheduledExecutorService.schedule(new Task("1"), 4L, TimeUnit.SECONDS);
        scheduledExecutorService.schedule(new Task("2"), 1L, TimeUnit.SECONDS);

    }

    void testScheduledExecutorService() {

    }

    // submit和execute的不同在于会返回一个 Future，可以通过这个Future控制Task （非阻塞获取结果）
    // Callable 有结果返回，Runnable 没有结果返回  （通过 Future.get()）
    // 那如何用 execute也能有一个 Future呢？  用 FutureTask，见 testExecute()
    void testSubmit() {
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        Future future = null;
        // <T> Future<T> submit(Callable<T> task); Callable有返回结果
//        future = executorService.submit(new TaskCallable(TimeUnit.SECONDS, 10L));
        // Future<?> submit(Runnable task);  Runnable没有返回结果
        future = executorService.submit(new Task("RunnableTask"));
//        future.cancel(true); // 强行中断
        Object result = null;
        try {
            result = future.get(); // 卡住一直等结果
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        System.out.println(result);
    }

    // void execute(Runnable)
    // interface RunnableFuture<V> extends Runnable, Future<V>
    // FutureTask 实现了 RunnableFuture，在 run中做的控制和结果返回，结果是 实现了Callable有返回
    // 其实submit的过程是一样的，也是通过 FutureTask 实现的
    void testExecute() {
        FutureTask<String> futureTask = new FutureTask<String>(new TaskCallable(5L));
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        executorService.execute(futureTask);
        while (!futureTask.isDone()) {
            ThreadUtil.printThread("Task not done");
            ThreadUtil.sleep(1L);
        }
        try {
            System.out.println(futureTask.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}
